/**
 * Copyright 2016 vip.com.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 * </p>
 **/

package spring.cloud.tasks.api.service.impl.statistics.analyzer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spring.cloud.tasks.api.domain.NameSpaceConfiguration;
import spring.cloud.tasks.api.domain.Timeout4AlarmJob;
import spring.cloud.tasks.api.service.ReportAlarmService;
import spring.cloud.tasks.api.service.helper.DashboardServiceHelper;
import spring.cloud.tasks.api.utils.TaskNodePath;
import spring.cloud.tasks.api.zookeeper.ZooKeeper;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author timmy.hu
 */
public class Timeout4AlarmJobAnalyzer {

    private static final Logger log = LoggerFactory.getLogger(Timeout4AlarmJobAnalyzer.class);
    private final List<Timeout4AlarmJob> timeout4AlarmJobList = new ArrayList<Timeout4AlarmJob>();
    private ReportAlarmService reportAlarmService;

    /**
     * 查找超时告警作业
     */
    public void analyze(ZooKeeper zooKeeper, List<Timeout4AlarmJob> oldTimeout4AlarmJobs,
                        String jobName, String jobDegree, NameSpaceConfiguration config) {
        Timeout4AlarmJob timeout4AlarmJob = new Timeout4AlarmJob(jobName, config.getNameSpace(), config.getDegree());
        if (isTimeout4AlarmJob(timeout4AlarmJob, oldTimeout4AlarmJobs, zooKeeper)) {
            timeout4AlarmJob.setJobDegree(jobDegree);
            addTimeout4AlarmJob(timeout4AlarmJob);
        }
    }

    private synchronized void addTimeout4AlarmJob(Timeout4AlarmJob timeout4AlarmJob) {
        timeout4AlarmJobList.add(timeout4AlarmJob);
    }

    /**
     * 如果配置了超时告警时间，而且running节点存在时间大于它，则告警
     */
    private boolean isTimeout4AlarmJob(Timeout4AlarmJob timeout4AlarmJob, List<Timeout4AlarmJob> oldTimeout4AlarmJobs,
                                       ZooKeeper zooKeeper) {
        String jobName = timeout4AlarmJob.getJobName();
        int timeout4AlarmSeconds = getTimeout4AlarmSeconds(zooKeeper, jobName);
        if (timeout4AlarmSeconds <= 0) {
            return false;
        }
        List<String> items = zooKeeper.getChildren(TaskNodePath.getExecutionNodePath(jobName));
        if (items == null || items.isEmpty()) {
            return false;
        }
        computeTimeoutItems(timeout4AlarmJob, zooKeeper, jobName, timeout4AlarmSeconds, items);
        if (!timeout4AlarmJob.getTimeoutItems().isEmpty()) {
            Timeout4AlarmJob oldJob = DashboardServiceHelper.findEqualTimeout4AlarmJob(timeout4AlarmJob, oldTimeout4AlarmJobs);
            if (oldJob != null) {
                timeout4AlarmJob.setRead(oldJob.isRead());
                if (oldJob.getUuid() != null) {
                    timeout4AlarmJob.setUuid(oldJob.getUuid());
                } else {
                    timeout4AlarmJob.setUuid(UUID.randomUUID().toString());
                }
            } else {
                timeout4AlarmJob.setUuid(UUID.randomUUID().toString());
            }
            if (!timeout4AlarmJob.isRead()) {
                try {
                    reportAlarmService.dashboardTimeout4AlarmJob(timeout4AlarmJob.getNamespace(), jobName,
                            timeout4AlarmJob.getTimeoutItems(), timeout4AlarmSeconds);
                } catch (Throwable t) {
                    log.error(t.getMessage(), t);
                }
            }
            return true;
        }
        return false;
    }

    private void computeTimeoutItems(Timeout4AlarmJob timeout4AlarmJob, ZooKeeper zooKeeper,
                                     String jobName, int timeout4AlarmSeconds, List<String> items) {
        long timeout4AlarmMills = timeout4AlarmSeconds * 1L * 1000;
        timeout4AlarmJob.setTimeout4AlarmSeconds(timeout4AlarmSeconds);
        for (String itemStr : items) {
            long ctime = zooKeeper.getCtime(TaskNodePath.getExecutionNodePath(jobName, itemStr, "running"));
            if (ctime > 0 && System.currentTimeMillis() - ctime > timeout4AlarmMills) {
                timeout4AlarmJob.getTimeoutItems().add(Integer.valueOf(itemStr));
            }
        }
    }

    private int getTimeout4AlarmSeconds(ZooKeeper zooKeeper, String jobName) {
        String timeout4AlarmSecondsStr = zooKeeper.getData(TaskNodePath.getConfigNodePath(jobName, "timeout4AlarmSeconds"));
        int timeout4AlarmSeconds = 0;
        if (timeout4AlarmSecondsStr != null) {
            try {
                timeout4AlarmSeconds = Integer.parseInt(timeout4AlarmSecondsStr);
            } catch (NumberFormatException e) {
                log.error(e.getMessage(), e);
            }
        }
        return timeout4AlarmSeconds;
    }

    public List<Timeout4AlarmJob> getTimeout4AlarmJobList() {
        return new ArrayList<Timeout4AlarmJob>(timeout4AlarmJobList);
    }

    public void setReportAlarmService(ReportAlarmService reportAlarmService) {
        this.reportAlarmService = reportAlarmService;
    }
}
